package com.example.tcp.client.store;


import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public abstract class AbstractDequeStore<T> implements IDequeStore<T> {

    protected AtomicBoolean running = new AtomicBoolean(true);
    protected final ReentrantLock lock = new ReentrantLock();
    protected final Condition notEmpty = lock.newCondition();

    @Override
    public boolean enqueue(T e)  {
        if(!running.get()) {
            return false;
        }
        boolean result = false;
        final ReentrantLock lock = this.lock;
        try {
            lock.lock();
            if((result = _enqueue(e))) {
                notEmpty.signal();
            }
        } finally {
            lock.unlock();
        }
        return result;
    }

    @Override
    public T dequeue() {
        final ReentrantLock lock = this.lock;
        try {
            lock.lock();
            while (running.get() && isEmpty()) {
                try {
                    notEmpty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if(!running.get()) {
                return null;
            }
            return _dequeue();
        }  finally {
            lock.unlock();
        }
    }

    @Override
    public void close() {
        final ReentrantLock lock = this.lock;
        running.set(false);
        try {
            lock.lock();
            notEmpty.signal();
            _close();
        } finally {
            lock.unlock();
        }
    }

    protected abstract boolean _enqueue(T e);

    protected abstract T _dequeue();

    protected abstract void _close();
}
